﻿#region

using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using dnlib.DotNet;
using dnlib.DotNet.Resources;
using dnlib.DotNet.Writer;
using dnlib.IO;

#endregion

namespace 更新程序
{
    internal class Program
    {
        private static string FileExt { get; set; }
        private static string Filename { get; set; }
        private static void Main()
        {
            FileExt = Path.GetExtension(Properties.Resources.FileName);
            Filename = Path.GetFileNameWithoutExtension(Properties.Resources.FileName);
            UpDateResx();
            DeleteItself();
        }

        public static void UpDateResx()
        {
            string  path = Properties.Resources.FileName;
            string resxName = Properties.Resources.Name;
            string resxValue = Properties.Resources.Value;
            var processes = Process.GetProcesses();
            Stopwatch st = new Stopwatch();
            st.Start();

            while (processes.FirstOrDefault(s => Filename == s.ProcessName) != null)
            {
                if (st.Elapsed > TimeSpan.FromSeconds(10))
                {
                    return;
                }
            }


            ModuleDefMD module = ModuleDefMD.Load(path);

            EmbeddedResource resx =
                (EmbeddedResource) module.Resources.Find(module.Assembly.Name + ".Properties.Resources.resources");

            ResourceElementSet elementSet = ResourceReader.Read(module, resx.Data);
            try
            {
                ResourceElement element = elementSet.ResourceElements.First(s => s.Name == resxName);
                element.ResourceData = new BuiltInResourceData(ResourceTypeCode.String, resxValue);
                elementSet.Add(element);

                MemoryStream ms = new MemoryStream();
                ResourceWriter.Write(module, ms, elementSet);
                resx.Data = new MemoryImageStream(0, ms.GetBuffer(), 0, ms.GetBuffer().Length);

                if (module.IsILOnly)
                    module.Write(Filename+"_tmp"+FileExt, new ModuleWriterOptions(module));
                else
                    module.NativeWrite(Filename + "_tmp" + FileExt);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                return;
            }
            module.Dispose();


        }


        /// <summary>
        ///     删除程序自身（本文地址：http://www.cnblogs.com/Interkey/p/DeleteItself.html）【推荐】
        /// </summary>
        private static void DeleteItself()
        {
            string selfName = Path.GetFileName(Process.GetCurrentProcess().MainModule.FileName);
            string vBatFile = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName) + "\\DeleteItself.bat";
            using (StreamWriter vStreamWriter = new StreamWriter(vBatFile, false, Encoding.Default))
            {
                vStreamWriter.Write(":move\r\n" +
                                    $" move /Y {Filename}_tmp{FileExt} {Filename}{FileExt}  \r\n" +
                                    $"if exist {Filename}_tmp{FileExt} goto move\r\n" +
                                    ":del\r\n" +
                                    $" del {selfName}\r\n" +
                                    $"if exist {selfName} goto del\r\n" +
                                    "del %0\r\n");
            }

            //************ 执行批处理
            WinExec(vBatFile, 0);    
            //************ 结束退出
            Environment.Exit(0);
        }


        [DllImport("kernel32.dll")]
        public static extern uint WinExec(string lpCmdLine, uint uCmdShow);
    }
}